package coco.usbhid

import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.driver.UsbSerialProber
import com.hoho.android.usbserial.util.SerialInputOutputManager
import java.io.IOException
import java.lang.Thread.sleep
import java.nio.charset.StandardCharsets

@SuppressLint("StaticFieldLeak")
object UsbManage {
    private const val ACTION_USB_PERMISSION = "com.coco.hid.USB_PERMISSION"
    var connection: UsbDeviceConnection? = null
    private var context: Context? = null
    var dataLength = 0
    var device: UsbDevice? = null
    var driver: UsbSerialDriver? = null
    var manager: UsbManager? = null
    var port: UsbSerialPort? = null
    var timeOut = 1000
    const val X1 = 1000
    const val Y1 = 80
    const val X2 = 900
    const val Y2 = 180

    fun init(context: Context): Boolean {
        this.context = context
        manager = context.getSystemService(Context.USB_SERVICE) as UsbManager
        val findAllDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
        if (findAllDrivers.isEmpty()) {
            return false
        }
        val usbSerialDriver = findAllDrivers[0]
        driver = usbSerialDriver
        device = usbSerialDriver.device
        requestPermission(device!!)
        return true
    }

    fun clampToInt(value: Double): Int {
        return when {
            value.isNaN() -> Int.MAX_VALUE // 返回 Int.MAX_VALUE 表示无效结果
            value < 0 -> 0
            value > Int.MAX_VALUE.toDouble() -> Int.MAX_VALUE
            else -> value.toInt()
        }
    }

    fun reverseTargetValue(y: Double): Int {
        if (Y1 == Y2) {
            return Int.MAX_VALUE // 返回 Int.MAX_VALUE 表示无效结果
        }

        val result = X1 + (y - Y1) * (X2 - X1) / (Y2 - Y1)
        return clampToInt(result)
    }

    data class MouseCoordinates(val x: Int, val y: Int)

    fun calculateMouseCoordinates(x: Double, y: Double): MouseCoordinates {
        val mouseY1 = (4095 * reverseTargetValue(y) / ScreenManager.getDeviceScreenWidth())
        val mouseX1 = (4095 * x / ScreenManager.getDeviceScreenHeight()).toInt()
        return MouseCoordinates(mouseX1, mouseY1)
    }
    fun convertToHIDCoordinates(
        screenX: Double,
        screenY: Double,
        hidMaxValue: Int
    ): Pair<Int, Int> {
        // 计算 HID 坐标
        val hidX = ((screenX * hidMaxValue) / ScreenManager.getDeviceScreenWidth()).toInt()
        val hidY = ((screenY * hidMaxValue) / ScreenManager.getAutoScreenHeight()).toInt()

        return Pair(hidX, hidY)
    }

    fun click(
        x: Double,
        y: Double,
    ): Boolean {
        if (ScreenManager.isLandscape()) {
            val coordinates = calculateMouseCoordinates(x, y)
            UsbManage.sendData(UsbManage.touchReport(3, coordinates.y, coordinates.x))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(0, 0, 0))
        } else {
            val (hidX, hidY) = convertToHIDCoordinates(x, y, 4095)
            UsbManage.sendData(UsbManage.touchReport(3, hidX, hidY))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(0, 0, 0))
        }
        return true
    }

    fun swipe(
        x: Double,
        y: Double,
        ex: Double,
        ey: Double
    ): Boolean {
        if (ScreenManager.isLandscape()) {
            val coordinates1 = calculateMouseCoordinates(x, y)
            val coordinates2 = calculateMouseCoordinates(ex, ey)
            UsbManage.sendData(UsbManage.touchReport(3,  coordinates1.y,coordinates1.x))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(3,  coordinates2.y,coordinates2.x))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(0, 0,0))
            return true
        } else {
            val (hidX, hidY) = convertToHIDCoordinates(x, y, 4095)
            val (hidEX, hidEY) = convertToHIDCoordinates(ex, ey, 4095)
            UsbManage.sendData(UsbManage.touchReport(3, hidX, hidY))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(3, hidEX, hidEY))
            sleep(100)
            UsbManage.sendData(UsbManage.touchReport(0, 0,0))
            return true
        }

    }

    fun swipe1(
        startX: Double,
        startY: Double,
        endX: Double,
        endY: Double,
        step: Double,
        delay: Long
    ): Boolean {
        val stepDelay = delay / step
        return performSwipe(startX, startY, endX, endY, step.toInt(), stepDelay.toLong())
    }

    // 通用滑动执行函数
    fun performSwipe(
        startX: Double,
        startY: Double,
        endX: Double,
        endY: Double,
        steps: Int,
        stepDelay: Long
    ): Boolean {
        // 计算总的滑动距离
        val distanceX = endX - startX
        val distanceY = endY - startY
        // 根据 X 和 Y 距离计算每一步的增量
        val stepSizeX = distanceX / steps
        val stepSizeY = distanceY / steps
        for (i in 1..steps) {
            // 每一步的滑动坐标
            val interpolatedX = startX + stepSizeX * i
            val interpolatedY = startY + stepSizeY * i

            // 动态判断是横屏还是竖屏
            if (ScreenManager.isLandscape()) {
                // 横屏模式，计算坐标
                val coordinates = calculateMouseCoordinates(interpolatedX, interpolatedY)
                // 发送横屏坐标
                UsbManage.sendData(UsbManage.touchReport(3,  coordinates.y,coordinates.x))
            } else {
                // 竖屏模式，转换为 HID 坐标
                val (hidX, hidY) = convertToHIDCoordinates(interpolatedX, interpolatedY, 4095)
                // 发送 HID 坐标
                UsbManage.sendData(UsbManage.touchReport(3, hidX, hidY))
            }

            // 延迟每个步骤，确保总滑动时间为 delay
            sleep(stepDelay)
        }
        UsbManage.sendData(UsbManage.touchReport(0, 0,0))
        // 结束滑动时，发送停止命令
        return true
    }


    fun release(
    ): Boolean {
        UsbManage.sendData(UsbManage.touchReport(0, 0,0))
        return true
    }


    fun press(
        x: Double,
        y: Double,
    ): Boolean {
        if (ScreenManager.isLandscape()) {
            val coordinates1 = calculateMouseCoordinates(x, y)
            UsbManage.sendData(UsbManage.touchReport(3,  coordinates1.y,coordinates1.x))
            return true
        } else {
            val (hidX, hidY) = convertToHIDCoordinates(x, y, 4095)
            UsbManage.sendData(UsbManage.touchReport(3, hidX, hidY))
            return true
        }
    }



    fun connect(): Boolean {
        val openDevice = manager!!.openDevice(device!!)
        connection = openDevice
        if (openDevice == null) {
            return false
        }
        val usbSerialPort = driver!!.ports[0]
        port = usbSerialPort
        return try {
            usbSerialPort.open(connection!!)
            usbSerialPort.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE)
            Thread.sleep(100)
            if (port!!.dtr) {
                true
            } else {
                port!!.dtr = true
                true
            }
        } catch (e: IOException) {
            false
        } catch (e: InterruptedException) {
            false
        }
    }

    fun getData(timeout: Int): String {
        try {
            if (!port!!.dtr) {
                port!!.dtr = true
            }
        } catch (e: IOException) {
            e.printStackTrace()
            return ""
        }
        try {
            Thread.sleep(50)
        } catch (_: InterruptedException) {
        }
        val bArr = ByteArray(64)
        return try {
            dataLength = port!!.read(bArr, timeout)
            String(bArr, StandardCharsets.UTF_8)
        } catch (e: IOException) {
            e.printStackTrace()
            return ""
        }
    }

    fun touchReport(buttons: Int, x: Int, y: Int): ByteArray {
        val xHigh = (x shr 8) and 0xFF
        val xLow = x and 0xFF
        val yHigh = (y shr 8) and 0xFF
        val yLow = y and 0xFF
        return byteArrayOf(
            0x03.toByte(),
            buttons.toByte(),
            xHigh.toByte(),
            xLow.toByte(),
            yHigh.toByte(),
            yLow.toByte()
        )
    }

    fun mouseReport(buttons: Int, x: Int, y: Int): ByteArray {
        return byteArrayOf(0x02.toByte(), buttons.toByte(), x.toByte(), y.toByte())
    }

    fun keyReport(modifiers: Int, keys: List<Int>): ByteArray {
        val extendedKeys = keys + List(6 - keys.size) { 0 }
        return byteArrayOf(
            0x01.toByte(),
            modifiers.toByte(),
            0x00.toByte()
        ) + extendedKeys.map { it.toByte() }.toByteArray()
    }

    fun sendData(data: ByteArray, timeout: Int = timeOut, toggleDTR: Boolean = true): String {
        if (toggleDTR) {
            try {
                port!!.setDTR(true) // 设置 DTR 信号
            } catch (e: IOException) {
                return e.message.toString() // 返回错误信息
            }
        }
        try {
            port!!.write(data, timeout) // 发送数据
        } catch (e: IOException) {
            return e.message.toString() // 返回错误信息
        }
        if (toggleDTR) {
            try {
                port!!.setDTR(false) // 重置 DTR 信号
            } catch (e: IOException) {
                return e.message.toString() // 返回错误信息
            }
        }
        return ""
    }

    fun sendData(data: String, timeout: Int = timeOut, toggleDTR: Boolean = true): String {
        if (toggleDTR) {
            try {
                port!!.setDTR(true)
            } catch (e: IOException) {
                return e.message.toString()
            }
        }
        port!!.write((data + "\r\n").toByteArray(StandardCharsets.UTF_8), timeout)
        if (toggleDTR) {
            try {
                port!!.setDTR(false)
            } catch (e: IOException) {
                return e.message.toString()
            }
        }
        return ""
    }

    fun isOpen(): Boolean {
        return port?.isOpen == true
    }

    fun getUsbDevice(): UsbDevice? {
        val deviceList = manager!!.deviceList
        return deviceList.values.firstOrNull()
    }

    fun requestPermission(usbDevice: UsbDevice?) {
        manager!!.requestPermission(
            usbDevice,
            PendingIntent.getBroadcast(
                context,
                0,
                Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE
            )
        )
    }

}



